package io.kiki.sba.registry.server.metadata.metadataServer.impl;

import io.kiki.sba.registry.common.model.Node;
import io.kiki.sba.registry.common.model.metaserver.NodeChangeResult;
import io.kiki.sba.registry.common.model.metaserver.nodes.CentralControlNode;
import io.kiki.sba.registry.common.model.metaserver.nodes.ClientInterfaceNode;
import io.kiki.sba.registry.common.model.metaserver.nodes.DataStoreNode;
import io.kiki.sba.registry.server.metadata.bootstrap.config.NodeConfig;
import io.kiki.sba.registry.server.metadata.lease.dataStoreNode.DataStoreNodeManager;
import io.kiki.sba.registry.server.metadata.lease.session.ClientInterfaceNodeManager;
import io.kiki.sba.registry.server.metadata.metadataServer.CurrentNodeClusterMetadataServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Component
public class DefaultMetaServerManager {

    @Autowired
    private CurrentNodeClusterMetadataServer currentDcMetaServer;

    @Autowired
    private ClientInterfaceNodeManager clientInterfaceNodeManager;

    @Autowired
    private DataStoreNodeManager dataStoreNodeManager;

    @Autowired
    private NodeConfig nodeConfig;

    public <T extends Node> NodeChangeResult<T> getSummary(Node.NodeType type) {
        switch (type) {
        case central_control:
            return (NodeChangeResult<T>) getMetaServerLists();
        case data_store:
            return getDataServerLists();
        case client_interface:
            return getSessionServerLists();
        default:
            break;
        }
        return null;
    }

    private NodeChangeResult getMetaServerLists() {
        NodeChangeResult<CentralControlNode> result = new NodeChangeResult<>(Node.NodeType.central_control);
        result.setLocalDataCenter(nodeConfig.getLocalDataCenter());
        Map<String, Map<String, CentralControlNode>> nodeMap = new HashMap<>();
        Map<String, Long> epochMap = new HashMap<>();

        nodeMap.put(nodeConfig.getLocalDataCenter(), transform(currentDcMetaServer.getList()));
        epochMap.put(nodeConfig.getLocalDataCenter(), currentDcMetaServer.getEpoch());
        result.setNodes(nodeMap);
        result.setDataCenterListVersions(epochMap);

        result.setVersion(currentDcMetaServer.getEpoch());
        return result;
    }

    private NodeChangeResult getSessionServerLists() {
        NodeChangeResult<ClientInterfaceNode> result = new NodeChangeResult<>(Node.NodeType.client_interface);
        result.setLocalDataCenter(nodeConfig.getLocalDataCenter());
        Map<String, Map<String, ClientInterfaceNode>> nodeMap = new HashMap<>();
        Map<String, Long> epochMap = new HashMap<>();
        nodeMap.put(nodeConfig.getLocalDataCenter(), transform(clientInterfaceNodeManager.getSessionServerMetaInfo().getList()));
        result.setNodes(nodeMap);
        result.setVersion(clientInterfaceNodeManager.getEpoch());
        result.setDataCenterListVersions(epochMap);
        return result;
    }

    private NodeChangeResult getDataServerLists() {
        NodeChangeResult<DataStoreNode> result = new NodeChangeResult<>(Node.NodeType.data_store);
        result.setLocalDataCenter(nodeConfig.getLocalDataCenter());
        Map<String, Map<String, DataStoreNode>> nodeMap = new HashMap<>();
        Map<String, Long> epochMap = new HashMap<>();
        nodeMap.put(nodeConfig.getLocalDataCenter(), transform(dataStoreNodeManager.getDataStoreNodeInfo().getList()));
        result.setNodes(nodeMap);
        result.setVersion(dataStoreNodeManager.getEpoch());
        result.setDataCenterListVersions(epochMap);
        return result;
    }

    private <T extends Node> Map<String, T> transform(List<T> nodes) {
        Map<String, T> map = new HashMap<>();
        for (T node : nodes) {
            map.put(node.getUrl().getIp(), node);
        }
        return map;
    }


    DefaultMetaServerManager setCurrentDcMetaServer(CurrentNodeClusterMetadataServer currentDcMetaServer) {
        this.currentDcMetaServer = currentDcMetaServer;
        return this;
    }


    DefaultMetaServerManager setSessionManager(ClientInterfaceNodeManager clientInterfaceNodeManager) {
        this.clientInterfaceNodeManager = clientInterfaceNodeManager;
        return this;
    }


    DefaultMetaServerManager setDataServerManager(DataStoreNodeManager dataStoreNodeManager) {
        this.dataStoreNodeManager = dataStoreNodeManager;
        return this;
    }


    DefaultMetaServerManager setNodeConfig(NodeConfig nodeConfig) {
        this.nodeConfig = nodeConfig;
        return this;
    }
}
